#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common/t_list.h"
#include "common/console.h"
#include "common/fdocs.h"
#include "t_types.h"

//#define console_error printf

F_DOCS_S *fdocs_Create(char *pchInBuf, int nLen, int nBlockSize)
{
	F_DOCS_S *pDocs = NULL;
	F_DOCS_BLOCK_H *pBlock = NULL;
	int i;
	int nBlocks = 0;

	pDocs = (F_DOCS_S *)malloc(sizeof(F_DOCS_S));
	if (pDocs == NULL)
	{
		console_error("can not malloc for fdocs\n");
		return NULL;
	}

	INIT_LIST_HEAD(&pDocs->head);
	pDocs->pchInBuf = pchInBuf;
	pDocs->nLen = nLen;

	nBlocks = nLen / nBlockSize;
	if ((nLen % nBlockSize) > 0)
	{
		nBlocks += 1;
	}
	pDocs->nBlockTotal = nBlocks;

	//	printf("input len:%d, blocks:%d\n", nLen, nBlocks);
	for (i = 0; i < nBlocks; i++)
	{
		pBlock = (F_DOCS_BLOCK_H *)malloc(sizeof(F_DOCS_BLOCK_H));
		if (pBlock == NULL)
		{
			console_error("can not malloc for fdocs block\n");
			goto _error;
		}
		pBlock->nBlockSerial = i;
		pBlock->nBlockTotal = nBlocks;
		pBlock->pvData = pchInBuf + i * nBlockSize;
		pBlock->nDataLen = nBlockSize;
		if (i == (nBlocks - 1))
		{
			pBlock->nDataLen = nLen - nBlockSize * i;
			//			printf("create pBlock->nDataLen:%d\n", pBlock->nDataLen);
		}
		T_ListAddTail(&pBlock->List, &pDocs->head);
		//		printf("add list addr:0x%x\n", (T_ADDR)&pBlock->List);
	}

	return pDocs;

_error:
	return NULL;
}

F_DOCS_S *fdocs_CreateEmpty(void)
{
	F_DOCS_S *pDocs = NULL;
	F_DOCS_BLOCK_H *pBlock = NULL;
	int i;
	int nBlocks = 0;

	pDocs = (F_DOCS_S *)malloc(sizeof(F_DOCS_S));
	if (pDocs == NULL)
	{
		console_error("can not malloc for fdocs\n");
		return NULL;
	}

	memset(pDocs, 0, sizeof(F_DOCS_S));

	INIT_LIST_HEAD(&pDocs->head);

	return pDocs;

_error:
	return NULL;
}

int fdocs_AddBlock(F_DOCS_S *pFdoc, int nBlockSerial, char *pData, int nLen)
{
	F_DOCS_BLOCK_H *pBlock = NULL;

	if (pFdoc == NULL || pData == NULL || nLen <= 0)
	{
		console_error("ptr is null!\n");
		return -1;
	}

	pBlock = (F_DOCS_BLOCK_H *)malloc(sizeof(F_DOCS_BLOCK_H));
	if (pBlock == NULL)
	{
		console_error("can not malloc for block ctx\n");
		goto _error;
	}
	memset(pBlock, 0, sizeof(F_DOCS_BLOCK_H));

	pBlock->pvData = (void *)malloc(nLen);
	if (pBlock->pvData == NULL)
	{
		console_error("can not malloc for data\n");
		goto _error;
	}

	memcpy((void *)pBlock->pvData, pData, nLen);
	pBlock->nBlockSerial = nBlockSerial;

	T_ListAddTail(&pBlock->List, &pFdoc->head);

	return 0;

_error:
	if (pBlock)
	{
		if (pBlock->pvData)
		{
			free((void *)pBlock->pvData);
		}
		free(pBlock);
	}
	return -1;
}

int fdocs_Destroy(F_DOCS_S *pFdocs)
{
	struct T_LIST_HEAD *pList = NULL;
	F_DOCS_BLOCK_H *pBlock = NULL;

	if (pFdocs == NULL)
	{
		console_error("fdocs_destroy() ptr is null\n");
		return -1;
	}

	T_LIST_FOR_EACH(pList, &pFdocs->head)
	{
		pBlock = T_LIST_ENTRY(pList, F_DOCS_BLOCK_H, List);
		//		printf("nBlockTotal:%d\n", pBlock->nBlockTotal);
		//		printf("nBlockSerial:%d\n", pBlock->nBlockSerial);
		T_ListDel(pList);
		pList = &pFdocs->head;
		free((void *)pBlock);
	}

	free((void *)pFdocs);

	return 0;
}

int fdocs_dump_txt(F_DOCS_S *pFdocs)
{
	int i;
	struct T_LIST_HEAD *pList = NULL;
	F_DOCS_BLOCK_H *pBlock = NULL;
	char abyText[64 * 1024];

	T_LIST_FOR_EACH(pList, &pFdocs->head)
	{
		//		printf("each list addr:0x%x\n", (unsigned int)pList);
		pBlock = T_LIST_ENTRY(pList, F_DOCS_BLOCK_H, List);
		printf("nBlockTotal:%d\n", pBlock->nBlockTotal);
		printf("nBlockSerial:%d\n", pBlock->nBlockSerial);
		memset(abyText, 0, sizeof(abyText));
		memcpy((void *)abyText, (void *)pBlock->pvData, pBlock->nDataLen);
		printf("text:%s\n", abyText);
	}

	return 0;
}

#if 0

int main(int argc, char** argv)
{

	FILE *fp = NULL;
	F_DOCS_S *pFdocs = NULL;
	char abyText[1024*1024];
	int nLen;

	fp = fopen(argv[1], "r");
	if(fp == NULL)
	{

		printf("can not open file:%s\n", argv[1]);
		return 0;
	}

	nLen = fread(abyText, 1, sizeof(abyText), fp);
	fclose(fp);

redo:
	pFdocs = fdocs_Create(abyText, nLen, 128, 1);
	if(pFdocs == NULL)
	{
		printf("fdocs_Create() error\n");
		return -1;
	}

	printf("now, dump blocks\n");

	fdocs_dump_txt(pFdocs);

	// destroy
	fdocs_Destroy(pFdocs);

	sleep(1);
//	goto redo;

	return 0;
}
#endif